package com.sinosoft.lk.core.helper;

import com.sinosoft.lk.core.config.SsoDefaultJedisConfig;
import com.sinosoft.lk.core.utils.SerializetionUtils;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import redis.clients.jedis.JedisPoolConfig;
import redis.clients.jedis.JedisShardInfo;
import redis.clients.jedis.Protocol.Command;
import redis.clients.jedis.ShardedJedis;
import redis.clients.jedis.ShardedJedisPool;
import redis.clients.jedis.commands.ProtocolCommand;

/**
 * @Author 绫小路
 * @Date 2021/3/4
 */
public class JedisHelper {

  private static Logger logger = LoggerFactory.getLogger(JedisHelper.class);
  private static JedisHelper jedisHelper;
  private static ShardedJedisPool shardedJedisPool;
  private static JedisPoolConfig jedisPoolConfig = new SsoDefaultJedisConfig();
  private static int connectionTimeout = 10000;
  /**
   * {redis/rediss}://{ip}:{port} or redis://{ip}:{port},redis://{ip}:{port}/{db} redis://account:123456@127.0.0.1:6379/5  => user=account
   * password=123456 host=127.0.0.1 port=6379 db=5
   */
  private static String address;

  private JedisHelper() {
    List<JedisShardInfo> jedisShardInfos = new ArrayList<>();
    if (address == null) {
      // default
      address = "redis://127.0.0.1:6379";
    }
    String[] addressArr = address.split(",");
    for (String a : addressArr) {
      JedisShardInfo jedisShardInfo = new JedisShardInfo(a);
      jedisShardInfo.setConnectionTimeout(connectionTimeout);
      jedisShardInfos.add(jedisShardInfo);
    }
    //create
    shardedJedisPool = new ShardedJedisPool(jedisPoolConfig, jedisShardInfos);
  }

  public static JedisHelper getInstance() {
    if (jedisHelper == null) {
      synchronized (JedisHelper.class) {
        if (jedisHelper == null) {
          try {
            jedisHelper = new JedisHelper();
          } catch (Exception e) {
            logger.error(e.getMessage(), e);
          }
        }
      }
    }
    return jedisHelper;
  }

  /**
   * @param address
   * @param config
   * @param connectionTimeout default 10000
   */
  public static void setConfig(String address, JedisPoolConfig config, int connectionTimeout) {
    JedisHelper.address = address;
    if (config == null) {
      jedisPoolConfig = new SsoDefaultJedisConfig();
    } else {
      jedisPoolConfig = config;
    }
    JedisHelper.connectionTimeout = connectionTimeout;
  }

  //--------------------- utils-------------------

  /**
   * tip: ShardedJedis.close();
   */
  public static ShardedJedis getShardedJedis() {
    return JedisHelper.getInstance().shardedJedisPool.getResource();
  }

  public static boolean ping() {
    ShardedJedis client = getShardedJedis();
    client.echo("connect redis!");
    client.close();
    return true;
  }

  public static void setString(String key, String value, int seconds) {
    ShardedJedis client = getShardedJedis();
    try {
      client.setex(key, seconds, value);
    } catch (Exception e) {
      logger.error(e.getMessage(), e);
    } finally {
      client.close();
    }
  }

  public static String getString(String key) {
    ShardedJedis client = getShardedJedis();
    String v = null;
    try {
      v = client.get(key);
    } catch (Exception e) {
      logger.error(e.getMessage(), e);
    } finally {
      client.close();
    }
    return v;
  }

  public static void setObject(String key, Object value, int seconds) {
    ShardedJedis client = getShardedJedis();
    try {
      client.setex(key.getBytes(), seconds, SerializetionUtils.serializetion(value));
    } catch (Exception e) {
      logger.error(e.getMessage(), e);
    } finally {
      client.close();
    }
  }

  public static Object getObject(String key) {
    ShardedJedis client = getShardedJedis();
    Object unserizlize = null;
    try {
      if (client.exists(key)) {
        unserizlize = SerializetionUtils.unserizlize(client.get(key.getBytes()));
      }
    } catch (IOException e) {
      logger.error(e.getMessage(), e);
    } finally {
      client.close();
    }
    return unserizlize;
  }

  public static void setStrHash(String key, Map<String, String> hash, int seconds) {
    ShardedJedis client = getShardedJedis();
    try {
      client.hset(key, hash);
      client.expire(key, seconds);
    } catch (Exception e) {
      logger.error(e.getMessage(), e);
    } finally {
      client.close();
    }
  }

  public static Map<String, String> getStrHash(String key) {
    ShardedJedis client = getShardedJedis();
    try {
      Map<String, String> map = client.hgetAll(key);
      if (map.isEmpty()) {
        return null;
      }
      return map;
    } catch (Exception e) {
      logger.error(e.getMessage(), e);
    } finally {
      client.close();
    }
    return null;
  }

  public static void setObjectHash(String key, Map<String, Object> hash, int seconds) {
    ShardedJedis client = getShardedJedis();
    try {
      Map<byte[], byte[]> map = new HashMap<>(hash.size());
      for (Map.Entry<String, Object> entry : hash.entrySet()) {
        map.put(entry.getKey().getBytes(), SerializetionUtils.serializetion(entry.getValue()));
      }
      client.hset(key.getBytes(), map);
      client.expire(key, seconds);
    } catch (Exception e) {
      logger.error(e.getMessage(), e);
    } finally {
      client.close();
    }
  }

  public static Map<String, Object> getObjectHash(String key) {
    ShardedJedis client = getShardedJedis();
    try {
      Map<byte[], byte[]> map = client.hgetAll(key.getBytes());
      if (map.isEmpty()) {
        return null;
      }
      Map<String, Object> hash = new HashMap<>(map.size());
      for (Map.Entry<byte[], byte[]> entry : map.entrySet()) {
        hash.put(new String(entry.getKey()), SerializetionUtils.unserizlize(entry.getValue()));
      }
      return hash;
    } catch (Exception e) {
      logger.error(e.getMessage(), e);
    } finally {
      client.close();
    }
    return null;
  }

  public static Long del(String key) {
    Long result = null;
    ShardedJedis client = getShardedJedis();
    try {
      result = client.del(key);
    } catch (Exception e) {
      logger.error(e.getMessage(), e);
    } finally {
      client.close();
    }
    return result;
  }

  public static Long dels(String[] keys) {
    ShardedJedis client = getShardedJedis();
    try {
      Object res = client.sendCommand(Command.DEL, keys);
      if (res != null) {
        return (Long) res;
      }
    } catch (Exception e) {
      logger.error(e.getMessage(), e);
    } finally {
      client.close();
    }
    return 0L;
  }

  public static String delAllTheDB() {
    String result = null;
    ShardedJedis client = getShardedJedis();
    try {
      Object o = client.sendCommand(Command.FLUSHDB);
      return new String((byte[]) o);
    } catch (Exception e) {
      logger.error(e.getMessage(), e);
    } finally {
      client.close();
    }
    return result;
  }

  public static boolean exists(String key) {
    Boolean result = null;
    ShardedJedis client = getShardedJedis();
    try {
      result = client.exists(key);
    } catch (Exception e) {
      logger.error(e.getMessage(), e);
    } finally {
      client.close();
    }
    return result;
  }

  /**
   * 设置过期时间
   *
   * @param key
   * @param seconds
   * @return
   */
  public static long expire(String key, int seconds) {
    Long result = null;
    ShardedJedis client = getShardedJedis();
    try {
      result = client.expire(key, seconds);
    } catch (Exception e) {
      logger.error(e.getMessage(), e);
    } finally {
      client.close();
    }
    return result;
  }

  public static Long ttl(String key) {
    ShardedJedis client = getShardedJedis();
    try {
      return client.ttl(key);
    } catch (Exception e) {
      logger.error(e.getMessage(), e);
    } finally {
      client.close();
    }
    return -2L;
  }

  public static void renameKey(String oldKey, String newKey) {
    ShardedJedis client = getShardedJedis();
    try {
      client.sendCommand(Command.RENAME, oldKey, newKey);
    } catch (Exception e) {
      logger.error(e.getMessage(), e);
    } finally {
      client.close();
    }
  }

  /**
   * sendCommand(Command.GET, "b");<br>
   *
   * @param cmd
   * @param args
   * @return
   */
  public static Object sendCommand(ProtocolCommand cmd, String... args) {
    ShardedJedis client = getShardedJedis();
    try {
      if (args == null) {
        return client.sendCommand(cmd);
      }
      java.lang.String[] strArray = {"1", "2", "3"};
      return client.sendCommand(cmd, args);
    } catch (Exception e) {
      logger.error(e.getMessage(), e);
    } finally {
      client.close();
    }
    return null;
  }

  public static void main(String[] args) throws IOException {
    String addr = "redis://127.0.0.1:6379/0";
    JedisHelper.getInstance();
    setObject("a", 123, 600);
    //renameKey("a","b");
    renameKey("a", "b");
    System.out.println(getObject("a"));
    System.out.println(getObject("b"));

    Map<String, Object> map = new HashMap<>();
    map.put("b", 4564);
    map.put("a", "asdasd");
    setObjectHash("asd", map, 555);
    System.out.println(getObjectHash("asd"));
    Map<String, Object> asd = getObjectHash("asd");
    for (Map.Entry<String, Object> entry : asd.entrySet()) {
      logger.info("key={}, value={}", entry.getKey(), entry.getValue());
      System.out.println(String.format("key=%s, value=%s", entry.getKey(), entry.getValue().toString()));
    }
    System.out.println("--------------------------");
    System.out.println(ttl("asd"));
    System.out.println(ttl("asdasda"));
    System.out.println("--------------------------");
    System.out.println(getObjectHash("12312"));

    System.out.println(del("12111113"));

    System.out.println("--------------------------");
    //delAllTheDB();
    Object o = sendCommand(Command.GET, "b");
    System.out.println(o);
    System.out.println(o != null ? new String((byte[]) o) : "null");
    //需要反序列化
    System.out.println(o != null ? SerializetionUtils.unserizlize((byte[]) o) : "null");
    System.out.println("-----------批量删除---------------");

    setString("a:11", "12312", 999);
    setString("b:11", "12312", 999);
    setString("a:1aaa1", "12312", 999);
    Object o1 = sendCommand(Command.KEYS, "a:*");
    List<Object> list = (List<Object>) o1;
    String[] ds = new String[list.size()];
    int i = 0;
    for (Object res : list) {
      ds[i] = new String((byte[]) res);
      i++;
      System.out.println(new String((byte[]) res));
    }
    System.out.println(ds);
    Long dels = dels(ds);
    System.out.println(dels);
    System.out.println("--------------------------");
  }
}
